/*
 *  Copyright (C) 2011 glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.common.defaults;

import org.balisunrise.common.DAO;
import java.io.Serializable;
import java.util.logging.Level;
import org.balisunrise.application.Application;
import org.balisunrise.application.Window;
import org.balisunrise.builder.CommonFactory;
import org.balisunrise.builder.FactoryException;
import org.balisunrise.common.Criterion;
import org.balisunrise.common.DAOProvider;
import org.balisunrise.common.EntityList;
import org.balisunrise.common.EntityLoader;
import org.balisunrise.common.EntitySelection;
import org.balisunrise.common.Query;
import org.balisunrise.common.Queryable;
import org.balisunrise.common.SelectionLoader;
import org.balisunrise.common.abstracts.AbstractBasic;
import org.balisunrise.common.NotFoundException;
import org.balisunrise.common.NotModifiedException;

/**
 * TODO: JavaDoc, PropertyChangeSupport
 * @author glauco
 */
public class DefaultSelectionLoader extends AbstractBasic
        implements SelectionLoader{

    private EntityList entityList;

    private EntityLoader entityLoader;

    private Window selectionWindow;

    private Serializable oldSelection;

    private Queryable queryable;

    private EntitySelection entitySelection;

    public String notFoundMessage;

    public EntityList getEntityList() {
        return entityList;
    }

    @Override
    public void setEntityList(EntityList entityList) {
        this.entityList = entityList;
    }

    public EntityLoader getEntityLoader() {
        return entityLoader;
    }

    @Override
    public void setEntityLoader(EntityLoader entityLoader) {
        this.entityLoader = entityLoader;
    }

    @Override
    public String getNotFoundMessage() {
        return notFoundMessage;
    }

    @Override
    public void setNotFoundMessage(String message) {
        this.notFoundMessage = message;
    }

    @Override
    public EntitySelection getEntitySelection() {
        return entitySelection;
    }

    @Override
    public void setEntitySelection(EntitySelection entitySelection) {
        this.entitySelection = entitySelection;
    }

    @Override
    public Queryable getQueryable() {
        return queryable;
    }

    @Override
    public void setQueryable(Queryable queryable) {
        this.queryable = queryable;
    }

    /**
     * Ação que seleciona uma entidade.<br>
     * Carrega atravéz do Queryable e um EntityLoader as entidades.<br>
     * Do retorno do EntityLoader se faz:<br><p>
     *   - Caso não retorne nenhuma entidade, é retornado nulo;<br>
     *   - Caso retorne uma unica entidade é retornado a mesma;<br>
     *   - Case retorne mais de uma entidade é chamado o EntitySelection e
     *      retornado a entidade selecionada.<br>
     *
     * @return A entitidade selecionada ou nulo.
     */
    @Override
    public Serializable selectEntity() 
            throws NotFoundException, NotModifiedException {

        if (entityList == null){
            CommonFactory factory = Application.get().getFactory();
            entityList = factory.createEntityList();
            entityList.setOwner(this);
        }

        if (entityLoader == null)
            try{
                CommonFactory factory = Application.get().getFactory();
                entityLoader = factory.createEntityLoader(
                        entitySelection.getEntityClass(),
                        entityList);
                entityLoader.setOwner(this);
            }catch(FactoryException fex){
                Application.get().getLogger().log(Level.SEVERE,
                        "SelectionLoader não pode construir EntityLoader: "
                        + fex.getMessage(), fex);
                return null;
            }

        if(queryable == null || !queryable.isModified())
            throw new NotModifiedException();

        // pega query
        Query query = queryable.getQuery();

        // verifica se tem algum valor em algum criterion
        boolean criterionsNull = true;
        for (Criterion c : query.getCriterions()) { 
            if(c.getValue() != null){
                criterionsNull = false;
                break;
            }
        }

        // se não tem informações chama pesquisa
        if(criterionsNull)
            return null;

        // carrega dados
        entityLoader.load(query);

        Serializable[] entities = entityLoader.getEntityList().getEntities();

        if (entities.length == 0)
            throw new NotFoundException(notFoundMessage);

        if (entities.length == 1)
            return storeEntitySelected(entities[0]);

        if(selectionWindow == null){
                selectionWindow = Application.get()
                        .getWindowsManager().createWindow(entitySelection);
                selectionWindow.setOwner(this);
                Application.get()
                        .getWindowsManager().showWindow(selectionWindow);
        } else
            Application.get().getWindowsManager().showWindow(selectionWindow);

        if(selectionWindow.getConfirmation()){
            return storeEntitySelected(entitySelection.getSelectedEntity());
        }else{
            throw new NotFoundException(notFoundMessage);
        }
    }

    private Serializable storeEntitySelected(Serializable entity){
        oldSelection = entity;
        return entity;
    }

    @Override
    public DAO getDAO() {
        if (owner instanceof DAOProvider)
            return ((DAOProvider)owner).getDAO();

        DAOProvider dp = VEAUtil.getDAOProvider(owner);

        if (dp != null)
            return dp.getDAO();
        
        return Application.get().getDaoManager().getDAO();
    }

}
